package com._51doit.day01.adv;

import com._51doit.day02.Function1;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 不使用Java8的Stream编程
 * 使用泛型定义一个更加高级的List
 *
 * 作用：通过这个例子让大家更加理解函数式编程，和深入理解泛型
 *
 * MyAdvList 要具备List的全部功能，并且可以扩展一些我想要的方法，比如map方法、filter方法、reduce方法等
 */
public class MyAdvList<T> extends ArrayList<T> {

    public MyAdvList<T> filter(MyFunction1<T, Boolean> func) {
        //定义一个新的List
        MyAdvList<T> nList = new MyAdvList<T>();
        //循环当前list中的数据
        for (T t : this) {
            //应用外部的过滤逻辑
            Boolean flag = func.apply(t);
            //将符合条件的数据添加到新的List中
            if (flag) {
                nList.add(t);
            }
        }
        //返回新的List
        return nList;
    }
//    public MyAdvList<T> map(MyFunction2<T> func){
//        //定义一个新的List
//        MyAdvList<T> nList = new MyAdvList<T>();
//        for (T t : this) {
//            T apply = func.apply(t);
//            nList.add(apply);
//        }
//        return nList ;
//    }
    public <R> MyAdvList<R> map(MyFunction1<T,R> func){
        //定义一个新的List
        MyAdvList<R> nList = new MyAdvList<>();
        for (T t : this) {
            R apply = func.apply(t);
            nList.add( apply);
        }
        return nList ;
    }
//    public <R> T reduce(MyFunction1<T,R> func){
//        R out = null ;
//        boolean isFirst = true ;
//        for (T t : this) {
//            if (isFirst){
//                out= (R) t;
//                isFirst=false ;
//            }else {
//
//            }
//        }
//    }

    public T reduce(MyFunction3<T,T,T> func){
        //定义一个新的List
        T out = this.get(0);
        for (int i = 1; i < this.size(); i++) {
            out = func.apply(out,this.get(i));
        }
        return out ;
    }

    public <R> MyAdvList<R> flatMap(Function1<T, Iterator<R>>func) {
        MyAdvList<R> nlist = new MyAdvList<>();
        for (T t : this) {
            Iterator<R> it = func.invote(t);
            while (it.hasNext()) {
                R r = it.next();
                nlist.add(r);
            }
        }
        return nlist;
    }
}
